#include "MGUI_LookFeel.h"
#include "MGUI_Engine.h"

namespace Myway {

	MGUI_LookFeel::MGUI_LookFeel(const TString128 & _name)
		: mName(_name)
		, mSkin(NULL)
	{
	}

	MGUI_LookFeel::~MGUI_LookFeel()
	{
		for (int i = 0; i < mChildren.Size(); ++i)
		{
			delete mChildren[i];
		}
	}

	void MGUI_LookFeel::SetSkin(const char * _source)
	{
		if (_source == NULL || _source[0] == 0)
			mSkin = NULL;
		else
			mSkin = TextureManager::Instance()->LoadTexture(_source, _source);
	}

	void MGUI_LookFeel::Init(MGUI_Widget * _widget) const
	{
		MGUI_Rect rect;
		
		rect.x1 = mUVRect[MGUI_WidgetState::Normal].DX();
		rect.y1 = mUVRect[MGUI_WidgetState::Normal].DY();

		_widget->SetRect(rect);
	}

	void MGUI_LookFeel::Affect(MGUI_Widget * _widget) const
	{
		const MGUI_Rect & rect = _widget->GetRect();

		MGUI_Rect client;

		client.x0 = mClientRect.dx0;
		client.y0 = mClientRect.dy0;

		client.x1 = rect.DX() - mClientRect.dx1;
		client.y1 = rect.DY() - mClientRect.dy1;

		client.x1 = Math::Maximum(client.x0, client.x1);
		client.y1 = Math::Maximum(client.y0, client.y1);

		_widget->SetClientRect(client);
	}

	MGUI_Rect MGUI_LookFeel::GetUVClientRect(int _state) const
	{
		MGUI_Rect rect;

		rect.x0 = mUVRect[_state].x0 + mClientRect.dx0;
		rect.y0 = mUVRect[_state].y0 + mClientRect.dy0;
		rect.x1 = mUVRect[_state].x1 - mClientRect.dx1;
		rect.y1 = mUVRect[_state].y1 - mClientRect.dy1;

		return rect;
	}

	MGUI_LookFeel * MGUI_LookFeel::GetChild(const TString128 & _name)
	{
		for (int i = 0; i < mChildren.Size(); ++i)
		{
			if (mChildren[i]->GetName() == _name)
				return mChildren[i];
		}

		return NULL;
	}

	const MGUI_LookFeel * MGUI_LookFeel::GetChild(const TString128 & _name) const
	{
		for (int i = 0; i < mChildren.Size(); ++i)
		{
			if (mChildren[i]->GetName() == _name)
				return mChildren[i];
		}

		return NULL;
	}

	MGUI_LookFeel * MGUI_LookFeel::Clone(const TString128 & _name)
	{
		MGUI_LookFeel * kClone = new MGUI_LookFeel(_name);

		kClone->mSkin = mSkin;

		kClone->mUVRect = mUVRect;
		kClone->mClientRect = mClientRect;

		for (int i = 0; i < mChildren.Size(); ++i)
		{
			kClone->AddChild(mChildren[i]->Clone(mChildren[i]->GetName()));
		}

		return kClone;
	}





	MGUI_LookFeelManager * MGUI_LookFeelManager::msInstance = NULL;

	MGUI_LookFeelManager::MGUI_LookFeelManager()
	{
		msInstance = this;
	}

	MGUI_LookFeelManager::~MGUI_LookFeelManager()
	{
		msInstance = NULL;

		Unload();
	}

	MGUI_LookFeel * _loadLookFeel(xml_node * node)
	{
		MGUI_LookFeel * lookfeel = new MGUI_LookFeel();

		xml_attri * name = node->first_attribute("name");
		xml_attri * skin = node->first_attribute("skin");
		xml_attri * client = node->first_attribute("client");

		lookfeel->SetName(name->value());

		if (skin)
		{
			lookfeel->SetSkin(skin->value());
		}

		if (client)
		{
			MGUI_ClientRect clRect;
			clRect.FromString(client->value());

			lookfeel->SetClientRect(clRect);
		}

		for (int i = 0; i < MGUI_WidgetState::Max; ++i)
		{
			const TString128 & stateString = MGUI_WidgetState::GetStateString(i);

			xml_node * state = node->first_node(stateString.c_str());

			if (state == NULL)
				continue;

			xml_attri * uv = state->first_attribute("uv");

			MGUI_Rect uvRect;
			uvRect.FromString(uv->value());

			lookfeel->SetUVRect(i, uvRect);
		}

		xml_node * child = node->first_node("Child");

		while (child)
		{
			_loadLookFeel(child);

			child = child->next_sibling("Child");
		}

		return lookfeel;
	}

	void MGUI_LookFeelManager::Load(const char * source)
	{
		Unload();

		DataStreamPtr stream = ResourceManager::Instance()->OpenResource(source);

		if (stream == NULL)
		{
			LOG_PRINT_FORMAT("Error: LookFeel File '%s' can't open.\n", source);
			return ;
		}

		mFilename = stream->GetName();

		xml_doc doc;
		XmlHelper::LoadXmlFromMem(doc, (char *)stream->GetData());

		xml_node * root = doc.first_node();

		if (root == NULL)
			return ;

		for (int i = 0; i < MGUI_WidgetType::Max; ++i)
		{
			const TString128 & typeString = MGUI_WidgetType::GetTypeString(i);

			xml_node * node = root->first_node(typeString.c_str());

			while (node != NULL)
			{
				MGUI_LookFeel * lookfeel = _loadLookFeel(node);

				mLookFeelGroup[i].PushBack(lookfeel);

				node = node->next_sibling(typeString.c_str());
			}
		}
	}

	void _saveLookFeel(MGUI_LookFeel * lookfeel, xml_node * node, xml_node * parent, xml_doc & doc)
	{
		{
			xml_attri * attri = doc.allocate_attribute_ex("name", lookfeel->GetName().c_str());
			node->append_attribute(attri);
		}

		if (lookfeel->GetSkin() != NULL)
		{
			xml_attri * skin = doc.allocate_attribute_ex("skin", lookfeel->GetSkin()->GetName().c_str());
			node->append_attribute(skin);
		}

		const MGUI_ClientRect & clRect = lookfeel->GetClientRect();
		if (clRect != MGUI_ClientRect())
		{
			xml_attri * attri = doc.allocate_attribute_ex("client", clRect.ToString().c_str());
			node->append_attribute(attri);
		}

		for (int i = 0; i < MGUI_WidgetState::Max; ++i)
		{
			const TString128 & stateString = MGUI_WidgetState::GetStateString(i);

			xml_node * state = doc.allocate_node(rapidxml::node_element, stateString.c_str());

			if (state == NULL)
				continue;

			{
				const MGUI_Rect & uvRect = lookfeel->GetUVRect(i);
				xml_attri * uv = doc.allocate_attribute_ex("uv", uvRect.ToString().c_str());

				state->append_attribute(uv);
			}

			node->append_node(state);
		}

		for (int i = 0; i < lookfeel->GetChildCount(); ++i)
		{
			xml_node * child = doc.allocate_node_ex(rapidxml::node_element, "Child");

			_saveLookFeel(lookfeel->GetChild(i), child, node, doc);
		}

		parent->append_node(node);
	}

	bool MGUI_LookFeelManager::Save()
	{
		if (mFilename == "")
			return false;

		std::ofstream file;
		file.open(mFilename.c_str());

		if (!file.is_open())
			return false;

		xml_doc doc;

		xml_node * root = doc.allocate_node(rapidxml::node_element, "MGUI_LookFeel");

		for (int i = 0; i < MGUI_WidgetType::Max; ++i)
		{
			const TString128 & typeString = MGUI_WidgetType::GetTypeString(i);

			for (int j = 0; j < mLookFeelGroup[i].Size(); ++j)
			{
				MGUI_LookFeel * lookfeel = mLookFeelGroup[i][j];
				xml_node * node = doc.allocate_node(rapidxml::node_element, typeString.c_str());

				_saveLookFeel(lookfeel, node, root, doc);
			}
		}

		doc.append_node(root);

		file << doc;

		file.close();

		return true;
	}

	void MGUI_LookFeelManager::Unload()
	{
		for (int i = 0; i < MGUI_WidgetType::Max; ++i)
		{
			for (int j = 0; j <  mLookFeelGroup[i].Size(); ++j)
			{
				delete mLookFeelGroup[i][j];
			}

			mLookFeelGroup[i].Clear();
		}

		mFilename = "";
	}

	void MGUI_LookFeelManager::AddLookFeel(int _type, MGUI_LookFeel * _lookfeel)
	{
		d_assert (GetLookFeel(_type, _lookfeel->GetName()) == NULL);

		mLookFeelGroup[_type].PushBack(_lookfeel);
	}

	void MGUI_LookFeelManager::RemoveLookFeel(int _type, MGUI_LookFeel * _lookfeel)
	{
		for (int i = 0; i < mLookFeelGroup[_type].Size(); ++i)
		{
			MGUI_LookFeel * k = mLookFeelGroup[_type][i];
			
			if (k == _lookfeel)
			{
				delete k;

				mLookFeelGroup[_type].Erase(i);

				return ;
			}
		}

		d_assert (0);
	}

	int MGUI_LookFeelManager::GetLookFeelCount(int _type)
	{
		return mLookFeelGroup[_type].Size();
	}

	MGUI_LookFeel * MGUI_LookFeelManager::GetLookFeel(int _type, int _index)
	{
		return mLookFeelGroup[_type][_index];
	}

	MGUI_LookFeel * MGUI_LookFeelManager::GetLookFeel(int _type, const TString128 & _name)
	{
		for (int i = 0; i < mLookFeelGroup[_type].Size(); ++i)
		{
			MGUI_LookFeel * k = mLookFeelGroup[_type][i];

			if (k->GetName() == _name)
				return k;
		}

		return NULL;
	}

}